#pragma once

#include <QtWidgets/QWidget>
#include "ui_ExMainHUD.h"

#include <wrl/client.h>
#include <string>
#include <d3d11_1.h>
#include "ExGameTimer.h"
#include "ExRenderThread.h"

#include <DirectXCollision.h>	// 已包含DirectXMath.h
#include <DirectXPackedVector.h>
#include <DirectXColors.h>
#include <d3dcompiler.h>
#include <filesystem>
#include <vector>

#include "Mouse.h"
#include "Keyboard.h"

// 添加所有要引用的库
#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "dxgi.lib")
#pragma comment(lib, "dxguid.lib")
#pragma comment(lib, "D3DCompiler.lib")
#pragma comment(lib, "winmm.lib")

class ExMainHUD : public QWidget
{
	Q_OBJECT

public Q_SLOTS:

	void UpdateRender();

public:

	ExMainHUD(QWidget *parent = Q_NULLPTR);

	virtual void OnResize();                  // 该父类方法需要在窗口大小变动的时候调用
	virtual void UpdateScene(float dt);       // 子类需要实现该方法，完成每一帧的更新
	virtual void DrawScene();                // 子类需要实现该方法，完成每一帧的绘制

	bool ExNativeEvent(const QByteArray &eventType, void *message, long *result);

	struct VertexPosColor
	{
		DirectX::XMFLOAT3 pos;
		DirectX::XMFLOAT4 color;
		static const D3D11_INPUT_ELEMENT_DESC inputLayout[2];
	};

	struct ConstantBuffer
	{
		DirectX::XMMATRIX world;
		DirectX::XMMATRIX view;
		DirectX::XMMATRIX proj;
	};

protected:

	virtual void mousePressEvent(QMouseEvent *event) override;

	virtual void mouseReleaseEvent(QMouseEvent *event) override;

	virtual void mouseMoveEvent(QMouseEvent *event) override;

private:

	bool InitDirect3D();        // Direct3D初始化

	bool InitEffect();

	bool InitResource();

	void CalculateFrameStats(); // 计算每秒帧数并在窗口显示

	// ------------------------------
	// CreateShaderFromFile函数
	// ------------------------------
	// [In]csoFileNameInOut 编译好的着色器二进制文件(.cso)，若有指定则优先寻找该文件并读取
	// [In]hlslFileName     着色器代码，若未找到着色器二进制文件则编译着色器代码
	// [In]entryPoint       入口点(指定开始的函数)
	// [In]shaderModel      着色器模型，格式为"*s_5_0"，*可以为c,d,g,h,p,v之一
	// [Out]ppBlobOut       输出着色器二进制信息
	HRESULT CreateShaderFromFile(
		const WCHAR* csoFileNameInOut,
		const WCHAR* hlslFileName,
		LPCSTR entryPoint,
		LPCSTR shaderModel,
		ID3DBlob** ppBlobOut);

	//重写虚函数
	virtual void resizeEvent(QResizeEvent *event) override; //当窗口尺寸改变时响应]
	virtual void closeEvent(QCloseEvent *event) override;

	QPaintEngine* paintEngine() const { return 0; }	// 允许dx渲染, 不重写这个会闪烁

	float AspectRatio()const;   // 获取屏幕宽高比


private:

	Ui::ExMainHUDClass ui;

	ExRenderThread* RenderThread;

	bool      m_AppPaused;       // 应用是否暂停
	bool	  m_Enable4xMsaa;	 // 是否开启4倍多重采样
	UINT      m_4xMsaaQuality;   // MSAA支持的质量等级

	ExGameTimer m_Timer;           // 计时器

	// 使用模板别名(C++11)简化类型名
	template <class T>
	using ComPtr = Microsoft::WRL::ComPtr<T>;
	// Direct3D 11
	ComPtr<ID3D11Device> m_pd3dDevice;                    // D3D11设备
	ComPtr<ID3D11DeviceContext> m_pd3dImmediateContext;   // D3D11设备上下文
	ComPtr<IDXGISwapChain> m_pSwapChain;                  // D3D11交换链
	// Direct3D 11.1
	ComPtr<ID3D11Device1> m_pd3dDevice1;                  // D3D11.1设备
	ComPtr<ID3D11DeviceContext1> m_pd3dImmediateContext1; // D3D11.1设备上下文
	ComPtr<IDXGISwapChain1> m_pSwapChain1;                // D3D11.1交换链
	// 常用资源
	ComPtr<ID3D11Texture2D> m_pDepthStencilBuffer;        // 深度模板缓冲区
	ComPtr<ID3D11RenderTargetView> m_pRenderTargetView;   // 渲染目标视图
	ComPtr<ID3D11DepthStencilView> m_pDepthStencilView;   // 深度模板视图
	D3D11_VIEWPORT m_ScreenViewport;                      // 视口

	// 派生类应该在构造函数设置好这些自定义的初始参数
	int m_ClientWidth;                                   // 视口宽度
	int m_ClientHeight;                                  // 视口高度

	ComPtr<ID3D11InputLayout> m_pVertexLayout;	// 顶点输入布局
	ComPtr<ID3D11Buffer> m_pVertexBuffer;		// 顶点缓冲区
	ComPtr<ID3D11Buffer> m_pIndexBuffer;		// 索引缓冲区
	ComPtr<ID3D11Buffer> m_pConstantBuffer;		// 常量缓冲区

	ComPtr<ID3D11VertexShader> m_pVertexShader;	// 顶点着色器
	ComPtr<ID3D11PixelShader> m_pPixelShader;	// 像素着色器
	ConstantBuffer m_CBuffer;	                // 用于修改GPU常量缓冲区的变量

	// 键鼠输入
	std::unique_ptr<DirectX::Mouse> m_pMouse;						// 鼠标
	DirectX::Mouse::ButtonStateTracker m_MouseTracker;				// 鼠标状态追踪器
	std::unique_ptr<DirectX::Keyboard> m_pKeyboard;					// 键盘
	DirectX::Keyboard::KeyboardStateTracker m_KeyboardTracker;		// 键盘状态追踪器
};
